package com.example.Aop;


import com.example.Annotation.ChooseDataSource;
import com.example.Enum.DataSourceEnum;
import com.example.Mybatis.DynamicDataSource.CustomContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Aspect
@Component
public class DynamicDataSourceAop {

    /**
     * 切面设置要选择的数据库
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("@annotation(com.example.Annotation.ChooseDataSource)")
    public Object permission(ProceedingJoinPoint joinPoint) throws Throwable {


        Object[] args = joinPoint.getArgs();
        Method method = getMethod(joinPoint, args);// 获取指定的方法
        // 获取数据库名称参数
        ChooseDataSource chooseDataSource = method.getAnnotation(ChooseDataSource.class);
        if (chooseDataSource != null) {
            //获取注解的数据库名称
            DataSourceEnum dataSourceName = chooseDataSource.dataSourceName();
            //判断当前数据库是否是有值
            if (CustomContextHolder.getCustomerType() != null) {
                DataSourceEnum[] values = DataSourceEnum.values();
                for (DataSourceEnum dataEnum : values) {
                    //如果枚举中的名称与注解数据库名称相同
                    if (dataEnum.getDatasourcename().equals(dataSourceName.getDatasourcename())) {
                        //再跟进枚举中对应的数据库的数据源信息进行匹配判断当前的数据源是否与枚举中的数据源一致
                        // 如果一致就过说明数据源是一致的不需要更新
                        if (dataEnum.getDatasourceBeanName().equals(CustomContextHolder.getCustomerType())) {
                            System.out.println("数据库相同不需要进行切换" + CustomContextHolder.getCustomerType());
                            return joinPoint.proceed();
                        } else {
//                            此种情况属于注解要求的数据源与现在使用的数据源不一致的情况，按照注解需求进行切换
                            CustomContextHolder.setCustomerType(dataEnum.getDatasourceBeanName());
                            System.out.println("切换新的数据库" + CustomContextHolder.getCustomerType());
                            return joinPoint.proceed();
                        }
                    }


                }

            }
        } else {
            throw new Exception(ChooseDataSource.class.getSimpleName() + "dataSourceName 必须填写");
        }

        return joinPoint.proceed();
    }

    private Method getMethod(ProceedingJoinPoint joinPoint, Object[] args) {
        String methodName = joinPoint.getSignature().getName();
        Class <? extends Object> clazz = joinPoint.getTarget().getClass();
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (methodName.equals(method.getName())) {
                return method;
            }
        }
        return null;
    }

    private Method getMethod(ProceedingJoinPoint joinPoint) throws NoSuchMethodException, SecurityException {
        Method method;
//        获取被代理的真实对象
        Class <?> targetclass = joinPoint.getTarget().getClass();
//        获取代理方法的名称
        String methodName = joinPoint.getSignature().getName();
//        获取代理方法的参数列表
        final Object[] args = joinPoint.getArgs();
        Class[] parameterTypes = new Class[args.length];
        for (int i = 0; i < args.length; i++) {
//            强转Class 为获取唯一的方法做准备
            parameterTypes[i] = (Class) args[i];
        }
//        通过真实对象进行反射获取到唯一的方法
        method = targetclass.getMethod(methodName, parameterTypes);
        return method;
    }
}
